from django.shortcuts import render
from django.views import View
from django.http import JsonResponse
import json
from django_redis import get_redis_connection
import base64, pickle

from apps.goods.models import SKU


# Create your views here.


class CartsView(View):

    def post(self, request):
        """
        保存购物车数据
        :param request:
        :return:
        """
        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = data_dict.get('sku_id')
        count = data_dict.get('count')
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        # 4-1、验证数据完整性
        if not all([sku_id, count, selected]):
            return JsonResponse({'code': 400, 'errmsg': '数据不完整'}, status=400)
        # 4-2、验证商品是否存在
        try:
            SKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，将数据保存在redis中
            # 6-1 建立redis链接
            conn = get_redis_connection('carts')
            # 6-2 将商品id和数量写入hash
            conn.hincrby('sku_count_%d' % user.id, sku_id, int(count))
            # 6-2 判断selected的状态是否为True，如果为True将商品id写入set
            if selected:
                conn.sadd('selected_%d' % user.id, sku_id)
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            response = JsonResponse({'code': 0, 'errmsg': 'ok'})
            # 7、用户未登录，将数据保存在cookie中
            # 7-1 现货区一下cookie，哦按段是否存储过
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2 如果存储过说明已经进行过base64 编码处理就需要进行解码获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 7-3 未存储 则复制一个空字典进行存储数据
                cart_dict = {}
            # 7-4 判断当前的sku_id是否已经存在字典中，存在说明已经添加过一次，需要对数量进行累加
            if sku_id in cart_dict:
                count += int(cart_dict[sku_id]['count'])
            # 7-5 将新数据保存在字典中
            cart_dict[sku_id] = {'count': count, 'selected': selected}
            # 7-6 对字典进行base64进行编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7-7 将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response

    # 获取购物车数据
    def get(self, request):
        """

        :param request:
        :return:
        """
        # 1 判断用户是否登录，不同状态用户获取不同数据
        user = request.user
        if user.is_authenticated:
            # ２　登录用户从ｒｅｄｉｓ中获取数据
            # 2-1、连接redis
            conn = get_redis_connection('carts')
            # 2-2、获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            # 2-3、获取set数据 {sku_id1,ski_id2}
            selected_sku = conn.smembers('selected_%d' % user.id)
            # 2-4、将两部分数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法
            # sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_sku  # sku_id在集合中返回True，不在返回False
                }


        else:
            # 3 未登录用户从cookie中获取数据
            # 3-1 未登录从ｃｏｏｋｉｅ中获取数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 3-2# 3-2、判断cookie数据是否存在，在写入cookie时指定过有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 3-3 存在 对cookie进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
        # 4 根据获取的sku_id查询sku表获取商品信息
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        # ５　构造返回的商品数据
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'count': cart_dict[sku.id]['count'],
                'selected': cart_dict[sku.id]['selected']
            })
        # 6返回结果

        return JsonResponse({'code': 400, 'errmsg': 'ok', 'cart_skus': cart_skus})

    # 修改购物车数据
    def put(self, request):
        """

        :param request:
        :return:
        """
        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = data_dict.get('sku_id')
        count = data_dict.get('count')
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        # 4-1、验证数据完整性
        if not all([sku_id, count, selected]):
            return JsonResponse({'code': 400, 'errmsg': '数据不完整'}, status=400)
        # 4-2、验证商品是否存在
        try:
            SKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，将数据保存在redis中
            # 6-1 建立redis链接
            conn = get_redis_connection('carts')
            # 6-2 覆盖redis以前的数据
            conn.hset('sku_count_%d' % user.id, sku_id, int(count))
            # 6-3、修改set中选中状态的sku_id
            if selected:
                # selected 为True 添加
                conn.sadd('selected_%d' % user.id, sku_id)
            else:
                # selected 为False 删除
                conn.srem('selected_%d' % user.id, sku_id)

            # 将修改后的数据返回
            cart_sku = {'count': count, 'selected': selected}
            return JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku})
        else:
            cart_sku = {'count': count, 'selected': selected}
            response = JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku})
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 7-3 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}

            # 覆盖以前的数据
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 转换成 密文数据
            cart_cookie = base64.b64encode(pickle.dumps(cart_cookie)).decode()

            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response

    def delete(self, request):
        """
        删除购物车
        :param request:
        :return:
        """
        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = data_dict.get('sku_id')
        # 4、验证数据
        # 4-2、验证商品是否存在
        try:
            SKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，删除ｒｅｄｉｓ购物车
            # 6-1 建立redis链接
            conn = get_redis_connection('carts')
            # 6-2、将商品id和数量从hash删除 hdel
            conn.hdel('sku_count_%d' % user.id, sku_id)
            # 6-3、删除set数据 srem
            conn.srem('selected_%d' % user.id, sku_id)
            return JsonResponse({'code': 0, 'errmsg': '删除购物车成功'})
        else:  # 未登录删除ｃｏｏｋｉｅ购物车
            response = JsonResponse({'code': 0, 'errmsg': '删除购物车成功'})
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('carts')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                return response
                # 解码后的字典可能是空字典
            if cart_dict:
                # 7-5、删除字典中数据
                del cart_dict[sku_id]
             # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 响应结果并将购物车数据写入到cookie
            response.set_cookie('carts', cart_cookie, max_age=24 * 30 * 3600)
            # 8、返回结果
            return response

class CartsSelectionView(View):
    """
    全选购物车
    """

    def put(self, request):
        """

        :param request:
        :return:
        """
        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 商品数量，商品id，选中状态
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        if selected:
            if not isinstance(selected, bool):
                return JsonResponse({'code': 400}, status=400)


        # 5、先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，将数据保存在redis中
            # 6-1 建立redis链接
            conn = get_redis_connection('carts')
            # 6-2 获取全部的商品ｓｋｕ——ｉｄ，从ｈａｓｈ中获取全部商品
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            sku_ids = sku_count.keys()

            # 6-3、修改全部商品的选中状态
            if selected:
                # selected 为True 添加
                conn.sadd('selected_%d' % user.id, *sku_ids)
            else:
                # selected 为False 删除
                conn.srem('selected_%d' % user.id, *sku_ids)

            # 将修改后的数据返回
            cart_sku = { 'selected': selected}
            return JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku})
        else:
            cart_sku = { 'selected': selected}
            response = JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku})
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 7-3 未存储，则赋值一个空字典进行存储数据
                return response

            # 将字典中所有数据进行更新
            for sku_id, count_selecte in cart_dict.items():
                count_selecte['selected'] = selected

            # 转换成 密文数据
            cart_cookie = base64.b64encode(pickle.dumps(cart_cookie)).decode()

            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response

class CartsSimpleView(View):

    # 获取购物车数据
    def get(self, request):
        """

        :param request:
        :return:
        """
        # 1 判断用户是否登录，不同状态用户获取不同数据
        user = request.user
        if user.is_authenticated:
            # ２　登录用户从ｒｅｄｉｓ中获取数据
            # 2-1、连接redis
            conn = get_redis_connection('carts')
            # 2-2、获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            # 2-3、获取set数据 {sku_id1,ski_id2}
            selected_sku = conn.smembers('selected_%d' % user.id)
            # 2-4、将两部分数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法
            # sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_sku  # sku_id在集合中返回True，不在返回False
                }


        else:
            # 3 未登录用户从cookie中获取数据
            # 3-1 未登录从ｃｏｏｋｉｅ中获取数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 3-2# 3-2、判断cookie数据是否存在，在写入cookie时指定过有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 3-3 存在 对cookie进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
        # 4 根据获取的sku_id查询sku表获取商品信息
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        # ５　构造返回的商品数据
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': cart_dict[sku.id]['count'],
            })
        # 6返回结果

        return JsonResponse({'code': 400, 'errmsg': 'ok', 'cart_skus': cart_skus})